package com.toby.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @desc: 用户切面，该切面一定要交给spring容器管理
 * @author: toby
 * @date: 2019/8/5 22:56
 */
@Aspect
//@Component
public class UserAspect {

    /**
     * For matching method execution join points. This is the primary pointcut designator to use when working with Spring AOP.
     * execution用于匹配方法执行 join points连接点，最小粒度方法
     * 详细用法参考：https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#aop-pointcuts-examples
     */
    @Pointcut("execution(* com.toby.service.UserService.*(..))")
    public void pointCutExecution(){}

    /**
     * Limits matching to join points (the execution of methods when using Spring AOP) where the arguments are instances of the given types.
     * 用于匹配当前执行的方法传入的参数为指定类型的执行方法
     */
    @Pointcut("args(java.lang.String)")
    public void pointCutArgs(){}

    /**
     * Limits matching to join points within certain types (the execution of a method declared within a matching type when using Spring AOP).
     * 用于匹配指定类型内的方法执行， within与execution相比，粒度更大，仅能实现到包和接口、类级别。而execution可以精确到方法的返回值，参数个数、修饰符、参数类型等
     */
    @Pointcut("within(com.toby.service.impl.UserServiceImpl)")
    public void pointCutWithin(){}

    /**
     * Limits matching to join points within types that have the given annotation (the execution of methods declared in types with the given annotation when using Spring AOP).
     * 用于匹配所以持有指定注解类型内的方法
     */
    @Pointcut("@within(com.toby.anno.Log)")
    public void pointCutWithinAnno(){}

    /**
     * Limits matching to join points (the execution of methods when using Spring AOP) where the target object (application object being proxied) is an instance of the given type.
     * 用于匹配当前目标对象类型的执行方法
     */
    @Pointcut("target(com.toby.service.impl.UserServiceImpl)")
    public void pointCutTarget(){}

    /**
     * Limits matching to join points (the execution of methods when using Spring AOP) where the class of the executing object has an annotation of the given type.
     * 用于匹配目标对象类型是否有指定的注解
     */
    @Pointcut("@target(com.toby.anno.Log)")
    public void pointCutTargetAnno(){}

    /**
     * Limits matching to join points (the execution of methods when using Spring AOP) where the bean reference (Spring AOP proxy) is an instance of the given type.
     * 用于匹配当前AOP代理对象类型的执行方法；注意是AOP代理对象的类型匹配
     */
    @Pointcut("this(com.toby.service.impl.UserServiceImpl)")
    public void pointCutThis(){}

    /**
     * Limits matching to join points where the subject of the join point (the method being executed in Spring AOP) has the given annotation.
     * 用于匹配当前执行方法持有指定注解的方法；
     */
    @Pointcut("@annotation(com.toby.anno.Log)")
    public void pointCutAnno(){}

    //@Before("pointCutThis()")
    public void before(){
        /*Object[] args = joinPoint.getArgs();
        for(Object arg : args){
            System.out.println(arg);
        }*/
        System.out.println("--------before--------");
    }

    //@After("pointCutThis()")
    public void after(){
        System.out.println("--------after--------");
    }

    @Around("pointCutExecution() && pointCutAnno()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("start around");
        String tempArgs="";
        Object[] args =pjp.getArgs();
        for (Object arg:args){
            if(arg.getClass().getSimpleName().equals("String")){
                tempArgs = arg + " around";
            }
        }
        Object retVal = pjp.proceed(new Object[]{tempArgs});
        System.out.println("end around");
        return retVal;
    }
}
